#pragma once
#include "Typedefs.hpp"
#include "TerrainMaterialManager.hpp"
#include "ImportExport.hpp"

namespace he
{
	class Map;

	class MapRenderer
	{
		// Typedefs
	public:
		typedef std::vector<Ogre::RaySceneQueryResultEntry> RayEntryContainer_t;
		typedef std::vector<Ogre::RenderOperation *> RenderOpVector_t;
	private:
		typedef std::map<std::string, TileMaxs_t> ObjectMap_t;
		//! Scene node vector.
		typedef std::vector<Ogre::SceneNode *> SceneNodeVector_t;
		//! Partition scene node.
		typedef std::vector<SceneNodeVector_t> PartitionSceneNodeVector_t;

		// Constants
	private:
		//! Map manual object name.
		static std::string const MAP_OBJECT_NAME;
		//! Highlight manual object name.
		static std::string const HIGHLIGHT_OBEJCT_NAME;
		//! Highlight material name.
		static std::string const HIGHLIGHT_MATERIAL_NAME;
		//! Highlight material name for center tile of selection.
		static std::string const HIGHLIGHT_MATERIAL_NAME_MAIN;
		//! Axis material.
		static std::string const AXIS_MATERIAL_NAME;
		//! Partition size.
		static unsigned char const PARTITION_SIZE = 10;

		// Attributes
	private:
		//! Map.
		Map const *m_pMap;
		//! Terrain material manager.
		TerrainMaterialManager const &m_TerrainMaterialManager;
		//! Ogre scene manager.
		Ogre::SceneManager &m_SceneManager;
		//! Material for highliting.
		Ogre::MaterialPtr m_HighlightMaterial;
		//! Scene node for highlite.
		Ogre::SceneNode* m_pHighlightSceneNode;
		//! Map of all partitions.
		ObjectMap_t m_Partitions;
		//! Highlight object.
		Ogre::ManualObject *m_pHighlightObject;
		//! Partition scene nodes.
		PartitionSceneNodeVector_t m_PartitionSceneNodeVector;

		// Operations
	public:
		//! Create map model.
		HE_ENGINE_API void create_map_model();
		//! Set deep of tile.
		HE_ENGINE_API void update_tile(TileContainer_t const &Tiles);
		//! Get tile from world coordinate
		HE_ENGINE_API TerrainTile const *get_tile(Ogre::RaySceneQueryResult const &Rays, Ogre::Ray const &ViewRay) const;
		//! Get tile by query.
		/*!
			Takes into account also heights. Uses internally get_tile() with
			ray scene query parameter.
		*/
		HE_ENGINE_API TerrainTile const *get_tile(Ogre::Vector3 const &Positon) const;
		//! Get tile by position.
		/*! Tile is only valid if whole terrain is ON ZX plane without heights.
		*/
		HE_ENGINE_API TerrainTile const *get_tile_flat(Ogre::Vector3 const &Positon) const;
		//! Highlite tile.
		HE_ENGINE_API void highlight_tile(TerrainTile const &Tile, std::uint_least8_t HighLightSize);
		//! Enable disable noise.
		/*!
			Noise is now controller through fragment program. The default
			(with noise) is called "splat_nois". The one without the noise
			is called "splat". On noise toggle only fragment programs are
			changed for current pass.
		*/
		HE_ENGINE_API void enable_noise(bool Enable);
		//! Get all partitions data.
		HE_ENGINE_API RenderOpVector_t const get_partitions_data() const;
		//! Get parition scene node.
		HE_ENGINE_API Ogre::SceneNode *partition_scene_node(std::uint_least8_t X, std::uint_least8_t Y) const;
		//! Get tile vertex vector.
		HE_ENGINE_API static Ogre::Vector3 tile_vertex(TerrainTile const &Tile, std::uint_least8_t Vertex);
	private:
		//! Update partition.
		void update_partition(TileMaxs_t const &MaxMin, Ogre::ManualObject &Object);
		//! Compute average normal for tiles.
		static Ogre::Vector3 compute_average_normal(TileContainer_t const &Tiles, unsigned char Vertex, TerrainTile const &CurrentTile);
		//! Get the map terrain material name.
		std::string const get_map_material() const;
		//! Get tile normalf for given triangle face.
		static Ogre::Vector3 tile_normal(TerrainTile const &Tile, std::uint_least8_t Face);

		// Construction/Destruction
	public:
		HE_ENGINE_API MapRenderer(Map const *pMap, TerrainMaterialManager const &TerrainMaterialManager, Ogre::SceneManager &Manager);
	};
} /*he*/
